/**
  ******************************************************************************
  * @file
  * @brief
  * @author 陈哲自动化
  * @version V1.0.0
  * @date 2018/07/17
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "dhcp.h"
#include "lwip_app.h"
#include "w5500_fun.h"
/* Private defines -----------------------------------------------------------*/

/* Private Struct  -----------------------------------------------------------*/

/* Private enum    -----------------------------------------------------------*/

/* Private Variable  ---------------------------------------------------------*/
CONFIG_MSG_DHCP  RecvMsg;
uint8_t*   DHCP_CHADDR      = EXTERN_DHCP_MAC;      // DHCP Client MAC address.  20180625 
uint8_t*   GET_SN_MASK      = EXTERN_DHCP_SN;      // Subnet mask received from the DHCP server
uint8_t*   GET_GW_IP        = EXTERN_DHCP_GW;     // Gateway ip address received from the DHCP server
uint8_t*   GET_DNS_IP       = EXTERN_DHCP_DNS;    // DNS server ip address received from the DHCP server
uint8_t*   GET_SIP          = EXTERN_DHCP_SIP;    // Local ip address received from the DHCP server
uint8_t    DHCP_SIP[4]      = {0,};      // DNS server ip address is discovered
uint8_t    DHCP_REAL_SIP[4] = {0,};      // For extract my DHCP server in a few DHCP servers
uint8_t    OLD_SIP[4];                   // Previous local ip address received from DHCP server

uint32_t dhcp_tick_next   = DHCP_WAIT_TIME ;

// Network information from DHCP Server
uint8_t OLD_allocated_ip[4]   = {0, };    // Previous IP address
uint8_t DHCP_allocated_ip[4]  = {0, };    // IP address from DHCP
uint8_t DHCP_allocated_gw[4]  = {0, };    // Gateway address from DHCP
uint8_t DHCP_allocated_sn[4]  = {0, };    // Subnet mask from DHCP
uint8_t DHCP_allocated_dns[4] = {0, };    // DNS address from DHCP

uint8_t HOST_NAME[] = DEVICE_TYPE; 
uint32_t  DHCP_XID        = DEFAULT_XID;				
uint8_t   EXTERN_DHCPBUF[1024];      
RIP_MSG*  pDHCPMSG = (RIP_MSG*)EXTERN_DHCPBUF;   // Pointer for the DHCP message 

uint8_t  dhcp_state       = STATE_DHCP_READY;          // DHCP client status
uint32_t dhcp_lease_time;         // Leased time
uint32_t dhcp_time       = 0;
uint8_t  dhcp_retry_count = 0;     // retry count

char ip_mode[12];//当前IP模式   DHCP_MOD  STATIC_MOD
//Pointer

//Array

//Const

/* Private function prototypes -----------------------------------------------*/
static void reset_DHCP_timeout(void);
static uint8_t check_DHCP_timeout(void);
static void default_ip_assign(void);
static void default_ip_update(void);
static void default_ip_conflict(void);
static int8_t parseDHCPMSG(void); // Check the DHCP state
static void   makeDHCPMSG(void);
static uint8_t DHCP_run(void);
static void  send_DHCP_DISCOVER(void);// Send the discovery message to the DHCP server
static void  send_DHCP_REQUEST(void);// Send the request message to the DHCP server
static void  send_DHCP_DECLINE(void);
static int8_t check_DHCP_leasedIP(void);         // Check the leased IP address

void (*dhcp_ip_assign)(void)   = default_ip_assign;     
void (*dhcp_ip_update)(void)   = default_ip_update;    
void (*dhcp_ip_conflict)(void) = default_ip_conflict;

//ucosiii variable -----------------------------------------------*/
//任务优先级
#define DHCP_TASK_PRIO     15       
//任务堆栈大小
#define DHCP_STK_SIZE      256   
//任务控制块
OS_TCB DhcpTaskTCB;
//任务堆栈
CPU_STK DHCP_TASK_STK[DHCP_STK_SIZE];
//任务函数
void dhcp_task(void *p_arg);
//任务状态
OS_ERR err;

/***********************************************************************************
 * @brief 第一次获取到IP 设置生效
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static void default_ip_assign(void)
{
    setSIPR(DHCP_allocated_ip);
    setSUBR(DHCP_allocated_sn);
    setGAR (DHCP_allocated_gw);	

	PPItemIWrite(PP_LOCAL_IP_CDT,(uint8_t*)DHCP_allocated_ip, 4);
	PPItemIWrite(PP_WAY_CDT,(uint8_t*)DHCP_allocated_gw, 4);       
	PPItemIWrite(PP_SUB_MASK_CDT,(uint8_t*)DHCP_allocated_sn, 4);
}

/***********************************************************************************
 * @brief IP租约到期，获取到的IP更新
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static void default_ip_update(void)
{
   setMR(MR_RST);
   getMR(); 
   default_ip_assign();
   setSHAR(DHCP_CHADDR);
}

/***********************************************************************************
 * @brief IP冲突 复位重新获取
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static void default_ip_conflict(void)
{
	setMR(MR_RST);
	getMR();
	setSHAR(DHCP_CHADDR);
}

/***********************************************************************************
 * @brief  生产DHCP包
 * ex:       
 * @par   
 * None
 * @retval
 **********************************************************************************/
static void makeDHCPMSG(void)
{
   uint8_t  bk_mac[6];
   uint8_t* ptmp;
   uint8_t  i;
	
   getSHAR(bk_mac);

	pDHCPMSG->op      = DHCP_BOOTREQUEST;
	pDHCPMSG->htype   = DHCP_HTYPE10MB;
	pDHCPMSG->hlen    = DHCP_HLENETHERNET;
	pDHCPMSG->hops    = DHCP_HOPS;
	ptmp              = (uint8_t*)(&pDHCPMSG->xid);
	*(ptmp+0)         = (uint8_t)((DHCP_XID & 0xFF000000) >> 24);
	*(ptmp+1)         = (uint8_t)((DHCP_XID & 0x00FF0000) >> 16);
  *(ptmp+2)         = (uint8_t)((DHCP_XID & 0x0000FF00) >>  8);
	*(ptmp+3)         = (uint8_t)((DHCP_XID & 0x000000FF) >>  0);   
	pDHCPMSG->secs    = DHCP_SECS;
	ptmp              = (uint8_t*)(&pDHCPMSG->flags);	
	*(ptmp+0)         = (uint8_t)((DHCP_FLAGSBROADCAST & 0xFF00) >> 8);
	*(ptmp+1)         = (uint8_t)((DHCP_FLAGSBROADCAST & 0x00FF) >> 0);

	pDHCPMSG->ciaddr[0] = 0;
	pDHCPMSG->ciaddr[1] = 0;
	pDHCPMSG->ciaddr[2] = 0;
	pDHCPMSG->ciaddr[3] = 0;

	pDHCPMSG->yiaddr[0] = 0;
	pDHCPMSG->yiaddr[1] = 0;
	pDHCPMSG->yiaddr[2] = 0;
	pDHCPMSG->yiaddr[3] = 0;

	pDHCPMSG->siaddr[0] = 0;
	pDHCPMSG->siaddr[1] = 0;
	pDHCPMSG->siaddr[2] = 0;
	pDHCPMSG->siaddr[3] = 0;

	pDHCPMSG->giaddr[0] = 0;
	pDHCPMSG->giaddr[1] = 0;
	pDHCPMSG->giaddr[2] = 0;
	pDHCPMSG->giaddr[3] = 0;

	pDHCPMSG->chaddr[0] = DHCP_CHADDR[0];
	pDHCPMSG->chaddr[1] = DHCP_CHADDR[1];
	pDHCPMSG->chaddr[2] = DHCP_CHADDR[2];
	pDHCPMSG->chaddr[3] = DHCP_CHADDR[3];
	pDHCPMSG->chaddr[4] = DHCP_CHADDR[4];
	pDHCPMSG->chaddr[5] = DHCP_CHADDR[5];

	for (i = 6; i < 16; i++)  pDHCPMSG->chaddr[i] = 0;
	for (i = 0; i < 64; i++)  pDHCPMSG->sname[i]  = 0;
	for (i = 0; i < 128; i++) pDHCPMSG->file[i]   = 0;

	pDHCPMSG->OPT[0] = (uint8_t)((MAGIC_COOKIE & 0xFF000000) >> 24);
	pDHCPMSG->OPT[1] = (uint8_t)((MAGIC_COOKIE & 0x00FF0000) >> 16);
	pDHCPMSG->OPT[2] = (uint8_t)((MAGIC_COOKIE & 0x0000FF00) >>  8);
	pDHCPMSG->OPT[3] = (uint8_t) (MAGIC_COOKIE & 0x000000FF) >>  0;
}

/***********************************************************************************
 * @brief 发送DHCP发现消息
 * ex:       寻找网络中是否有DHCP服务器
 * @par   
 * None
 * @retval
 **********************************************************************************/
static void send_DHCP_DISCOVER(void)
{
	uint8_t ip[4];
	uint16_t k = 0;
  uint8_t host_name[18]; 
	
  makeDHCPMSG();
	
   k = 4;     // beacaue MAGIC_COOKIE already made by makeDHCPMSG()
   
	// Option Request Param
	pDHCPMSG->OPT[k++] = dhcpMessageType;
	pDHCPMSG->OPT[k++] = 0x01;
	pDHCPMSG->OPT[k++] = DHCP_DISCOVER;
	
	// Client identifier
	pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
	pDHCPMSG->OPT[k++] = 0x07;
	pDHCPMSG->OPT[k++] = 0x01;
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[0];
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[1];
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[2];
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[3];
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[4];
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[5];
	
	// host name
	pDHCPMSG->OPT[k++] = hostName;
	sprintf((char*)host_name,"%.11s-%02X%02X%02X",DEVICE_TYPE,DHCP_CHADDR[3],DHCP_CHADDR[4],DHCP_CHADDR[5]); 
  	
  pDHCPMSG->OPT[k++] = strlen((char*)host_name);
  
  strcpy((char*)(&(pDHCPMSG->OPT[k])),(char*)host_name);
  
  k+=strlen((char*)host_name);		

	pDHCPMSG->OPT[k++] = dhcpParamRequest;
	pDHCPMSG->OPT[k++] = 0x06;
	pDHCPMSG->OPT[k++] = subnetMask;
	pDHCPMSG->OPT[k++] = routersOnSubnet;
	pDHCPMSG->OPT[k++] = dns;
	pDHCPMSG->OPT[k++] = domainName;
	pDHCPMSG->OPT[k++] = dhcpT1value;
	pDHCPMSG->OPT[k++] = dhcpT2value;
	pDHCPMSG->OPT[k++] = endOption;

	// send broadcasting packet
	ip[0] = 255;
	ip[1] = 255;
	ip[2] = 255;
	ip[3] = 255;

	sendto(SOCK_DHCP, (uint8_t *)pDHCPMSG, sizeof(RIP_MSG), ip, DHCP_SERVER_PORT);
}

/***********************************************************************************
 * @brief 发送DHCP请求信息
 * ex:       网络中有DHCP服务器，请求分配IP
 * @par   
 * None
 * @retval
 **********************************************************************************/
static void send_DHCP_REQUEST(void)
{
//	int i;
	uint8_t ip[4];
	uint16_t k = 0;
  uint8_t host_name[18]; 
	
  makeDHCPMSG();

   if(dhcp_state == STATE_DHCP_LEASED || dhcp_state == STATE_DHCP_REREQUEST)
   {
   	*((uint8_t*)(&pDHCPMSG->flags))   = ((DHCP_FLAGSUNICAST & 0xFF00)>> 8);
   	*((uint8_t*)(&pDHCPMSG->flags)+1) = (DHCP_FLAGSUNICAST & 0x00FF);
   	pDHCPMSG->ciaddr[0] = DHCP_allocated_ip[0];
   	pDHCPMSG->ciaddr[1] = DHCP_allocated_ip[1];
   	pDHCPMSG->ciaddr[2] = DHCP_allocated_ip[2];
   	pDHCPMSG->ciaddr[3] = DHCP_allocated_ip[3];
   	ip[0] = DHCP_SIP[0];
   	ip[1] = DHCP_SIP[1];
   	ip[2] = DHCP_SIP[2];
   	ip[3] = DHCP_SIP[3];   	   	   	
   }
   else
   {
   	ip[0] = 255;
   	ip[1] = 255;
   	ip[2] = 255;
   	ip[3] = 255;   	   	   	
   }
   
   k = 4;      // beacaue MAGIC_COOKIE already made by makeDHCPMSG()
	
	// Option Request Param.
	pDHCPMSG->OPT[k++] = dhcpMessageType;
	pDHCPMSG->OPT[k++] = 0x01;
	pDHCPMSG->OPT[k++] = DHCP_REQUEST;

	pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
	pDHCPMSG->OPT[k++] = 0x07;
	pDHCPMSG->OPT[k++] = 0x01;
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[0];
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[1];
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[2];
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[3];
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[4];
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[5];

   if(ip[3] == 255)  // if(dchp_state == STATE_DHCP_LEASED || dchp_state == DHCP_REREQUEST_STATE)
   {
		pDHCPMSG->OPT[k++] = dhcpRequestedIPaddr;
		pDHCPMSG->OPT[k++] = 0x04;
		pDHCPMSG->OPT[k++] = DHCP_allocated_ip[0];
		pDHCPMSG->OPT[k++] = DHCP_allocated_ip[1];
		pDHCPMSG->OPT[k++] = DHCP_allocated_ip[2];
		pDHCPMSG->OPT[k++] = DHCP_allocated_ip[3];
	
		pDHCPMSG->OPT[k++] = dhcpServerIdentifier;
		pDHCPMSG->OPT[k++] = 0x04;
		pDHCPMSG->OPT[k++] = DHCP_SIP[0];
		pDHCPMSG->OPT[k++] = DHCP_SIP[1];
		pDHCPMSG->OPT[k++] = DHCP_SIP[2];
		pDHCPMSG->OPT[k++] = DHCP_SIP[3];
	}

	// host name
	pDHCPMSG->OPT[k++] = hostName;
	
	sprintf((char*)host_name,"%.11s-%02X%02X%02X",DEVICE_TYPE,DHCP_CHADDR[3],DHCP_CHADDR[4],DHCP_CHADDR[5]);
  
  
  pDHCPMSG->OPT[k++] = (uint8_t)strlen((char*)host_name);
  
  strcpy((char*)(&(pDHCPMSG->OPT[k])),(char*)host_name);
  
  k+=(uint8_t)strlen((char*)host_name);			
	
	pDHCPMSG->OPT[k++] = dhcpParamRequest;
	pDHCPMSG->OPT[k++] = 0x08;
	pDHCPMSG->OPT[k++] = subnetMask;
	pDHCPMSG->OPT[k++] = routersOnSubnet;
	pDHCPMSG->OPT[k++] = dns;
	pDHCPMSG->OPT[k++] = domainName;
	pDHCPMSG->OPT[k++] = dhcpT1value;
	pDHCPMSG->OPT[k++] = dhcpT2value;
	pDHCPMSG->OPT[k++] = performRouterDiscovery;
	pDHCPMSG->OPT[k++] = staticRoute;
	pDHCPMSG->OPT[k++] = endOption;

  sendto(SOCK_DHCP, (uint8_t *)pDHCPMSG, sizeof(RIP_MSG), ip, DHCP_SERVER_PORT);
}

/***********************************************************************************
 * @brief 发送DHCP释放信息
 * ex:       客户端收到服务器返回的 DHCP-ACK 确认报文后，会以广播的方式发送免费 ARP 报文，探测是否有主机使用服务器分配的 IP 地址，
 * @par        如果在规定的时间内没有收到回应，客户端才使用此地址。
 * None          否则，客户端会发送 DHCP-DECLINE 报文给 DHCP 服务器，并重新申请 IP 地址。
 * @retval
 **********************************************************************************/
static void send_DHCP_DECLINE(void)
{
//	int i;
	uint8_t ip[4];
	uint16_t k = 0;
	
	makeDHCPMSG();

   k = 4;      // beacaue MAGIC_COOKIE already made by makeDHCPMSG()
   
	*((uint8_t*)(&pDHCPMSG->flags))   = ((DHCP_FLAGSUNICAST & 0xFF00)>> 8);
	*((uint8_t*)(&pDHCPMSG->flags)+1) = (DHCP_FLAGSUNICAST & 0x00FF);

	// Option Request Param.
	pDHCPMSG->OPT[k++] = dhcpMessageType;
	pDHCPMSG->OPT[k++] = 0x01;
	pDHCPMSG->OPT[k++] = DHCP_DECLINE;

	pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
	pDHCPMSG->OPT[k++] = 0x07;
	pDHCPMSG->OPT[k++] = 0x01;
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[0];
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[1];
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[2];
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[3];
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[4];
	pDHCPMSG->OPT[k++] = DHCP_CHADDR[5];

	pDHCPMSG->OPT[k++] = dhcpRequestedIPaddr;
	pDHCPMSG->OPT[k++] = 0x04;
	pDHCPMSG->OPT[k++] = DHCP_allocated_ip[0];
	pDHCPMSG->OPT[k++] = DHCP_allocated_ip[1];
	pDHCPMSG->OPT[k++] = DHCP_allocated_ip[2];
	pDHCPMSG->OPT[k++] = DHCP_allocated_ip[3];

	pDHCPMSG->OPT[k++] = dhcpServerIdentifier;
	pDHCPMSG->OPT[k++] = 0x04;
	pDHCPMSG->OPT[k++] = DHCP_SIP[0];
	pDHCPMSG->OPT[k++] = DHCP_SIP[1];
	pDHCPMSG->OPT[k++] = DHCP_SIP[2];
	pDHCPMSG->OPT[k++] = DHCP_SIP[3];

	pDHCPMSG->OPT[k++] = endOption;

	//send broadcasting packet
	ip[0] = 0xFF;
	ip[1] = 0xFF;
	ip[2] = 0xFF;
	ip[3] = 0xFF;


	sendto(SOCK_DHCP, (uint8_t *)pDHCPMSG, sizeof(RIP_MSG), ip, DHCP_SERVER_PORT);
}

/***********************************************************************************
 * @brief 解析来自服务器的数据包
 * ex:    
 * @par   
 * None
 * @retval
 **********************************************************************************/
static int8_t parseDHCPMSG(void)
{
	uint8_t svr_addr[6];
	uint16_t  svr_port;
	uint16_t len;

	uint8_t * p;
	uint8_t * e;
	uint8_t type;
	uint8_t opt_len;
   
  if((len = getSn_RX_RSR(SOCK_DHCP)) > 0)
   {		
   	  len = recvfrom(SOCK_DHCP, (uint8_t *)pDHCPMSG, len, svr_addr, &svr_port);  
   }
   else return 0;
	if (svr_port == DHCP_SERVER_PORT) {
      // compare mac address
		if ( (pDHCPMSG->chaddr[0] != DHCP_CHADDR[0]) || (pDHCPMSG->chaddr[1] != DHCP_CHADDR[1]) ||
		     (pDHCPMSG->chaddr[2] != DHCP_CHADDR[2]) || (pDHCPMSG->chaddr[3] != DHCP_CHADDR[3]) ||
		     (pDHCPMSG->chaddr[4] != DHCP_CHADDR[4]) || (pDHCPMSG->chaddr[5] != DHCP_CHADDR[5])   )		
			    return 0;    
    type = 0;
		p = (uint8_t *)(&pDHCPMSG->op);//2
		p = p + 240;      // 240 = sizeof(RIP_MSG) + MAGIC_COOKIE size in RIP_MSG.opt - sizeof(RIP_MSG.opt)
		e = p + (len - 240);
		
		while ( p < e ) {
			switch ( *p ) {
   			case endOption :
   			   p = e;   // for break while(p < e)
   				break;
        case padOption :
   				p++;
   				break;
   			case dhcpMessageType :
   				p++;
   				p++;
   				type = *p++;
   				break;
   			case subnetMask :
   				p++;
   				p++;
   				DHCP_allocated_sn[0] = *p++;
   				DHCP_allocated_sn[1] = *p++;
   				DHCP_allocated_sn[2] = *p++;
   				DHCP_allocated_sn[3] = *p++;
   				break;
   			case routersOnSubnet :
   				p++;
   				opt_len = *p++;       
   				DHCP_allocated_gw[0] = *p++;
   				DHCP_allocated_gw[1] = *p++;
   				DHCP_allocated_gw[2] = *p++;
   				DHCP_allocated_gw[3] = *p++;
   				p = p + (opt_len - 4);
   				break;
   			case dns :
   				p++;                  
   				opt_len = *p++;       
   				DHCP_allocated_dns[0] = *p++;
   				DHCP_allocated_dns[1] = *p++;
   				DHCP_allocated_dns[2] = *p++;
   				DHCP_allocated_dns[3] = *p++;
   				p = p + (opt_len - 4);
   				break;
   			case dhcpIPaddrLeaseTime :
   				p++;
   				opt_len = *p++;
   				dhcp_lease_time  = *p++;
   				dhcp_lease_time  = (dhcp_lease_time << 8) + *p++;
   				dhcp_lease_time  = (dhcp_lease_time << 8) + *p++;
   				dhcp_lease_time  = (dhcp_lease_time << 8) + *p++;
   				break;
   			case dhcpServerIdentifier :
   				p++;
   				opt_len = *p++;
   				DHCP_SIP[0] = *p++;
   				DHCP_SIP[1] = *p++;
   				DHCP_SIP[2] = *p++;
   				DHCP_SIP[3] = *p++;
   				break;
   			default :
   				p++;
   				opt_len = *p++;
   				p += opt_len;
   				break;
			} // switch
		} // while
	} // if
	return	type;
}



/***********************************************************************************
 * @brief 检查DHCP服务器分配的IP是否有效
 * ex:       是否被占用
 * @par   
 * None
 * @retval
 **********************************************************************************/
static int8_t check_DHCP_leasedIP(void)
{
	uint8_t tmp;
	int32_t ret;

	//WIZchip RCR value changed for ARP Timeout count control
	tmp = getRCR();
	setRCR(0x03);
	// IP conflict detection : ARP request - ARP reply
	// Broadcasting ARP Request for check the IP conflict using UDP sendto() function
	ret = sendto(SOCK_DHCP, (uint8_t *)"CHECK_IP_CONFLICT", 17, DHCP_allocated_ip, 5000);

	// RCR value restore
	setRCR(tmp);

	if(ret){
		// Received ARP reply or etc : IP address conflict occur, DHCP Failed
		send_DHCP_DECLINE();
		ret = dhcp_time;
		while((dhcp_time - ret) < 2) ;   // wait for 1s over; wait to complete to send DECLINE message;

		return 0;
	}
	else 
	{
			// UDP send Timeout occurred : allocated IP address is unique, DHCP Success
		return 1;		
	}
}	


/***********************************************************************************
 * @brief DHCP功能初始化
 * ex:       
 * @par   
 * None
 * @retval
 **********************************************************************************/
void init_dhcp_client(void)
{
  //uint8_t txsize[MAX_SOCK_NUM] = {2,2,2,2,2,2,2,2};
  //uint8_t rxsize[MAX_SOCK_NUM] = {2,2,2,2,2,2,2,2};
  //uint8_t ip_broadcast[4]={255,};
  uint8_t ip_0[4]={0,};
  DHCP_XID = 0x12345678;
  memset(OLD_SIP,0,sizeof(OLD_SIP));
  memset(DHCP_SIP,0,sizeof(DHCP_SIP));
  memset(DHCP_REAL_SIP,0,sizeof(GET_SN_MASK));

  iinchip_init();
  
  setSHAR(ConfigMsg.mac);//设置物理地址
  setSUBR(ip_0);         //设置子网掩码
  setGAR(ip_0);          //设置网关
  setSIPR(ip_0);         //设置IP
 
  //w5500sysinit(txsize, rxsize); 
  //clear ip setted flag

  dhcp_state = STATE_DHCP_READY;  
  sprintf((char*)ip_mode,"DHCP_MODE");//工作区域
  //创建 msgq send 任务
  OSTaskCreate((OS_TCB    * )&DhcpTaskTCB,
               (CPU_CHAR  * )"dhcp task",
               (OS_TASK_PTR )dhcp_task,
               (void      * )0,
               (OS_PRIO     )DHCP_TASK_PRIO,
               (CPU_STK   * )&DHCP_TASK_STK[0],
               (CPU_STK_SIZE)DHCP_STK_SIZE/10,
               (CPU_STK_SIZE)DHCP_STK_SIZE,
               (OS_MSG_QTY  )0,
               (OS_TICK     )0,
               (void      * )0,
               (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
               (OS_ERR    * )&err);
}

/***********************************************************************************
 * @brief DHCP超时复位计时
 * ex:    
 * @par   
 * None
 * @retval
 **********************************************************************************/
static void reset_DHCP_timeout(void)
{
	dhcp_time = 0;
	dhcp_tick_next = DHCP_WAIT_TIME;
	dhcp_retry_count = 0;
}

/***********************************************************************************
 * @brief DHCP超时判断
 * ex:    
 * @par   
 * None
 * @retval
 **********************************************************************************/
static uint8_t check_DHCP_timeout(void)
{
	uint8_t ret = DHCP_RUNNING;
	if (dhcp_retry_count < MAX_DHCP_RETRY) {
		if (dhcp_tick_next < dhcp_time) {
   
			switch ( dhcp_state ) {
				case STATE_DHCP_DISCOVER :
					send_DHCP_DISCOVER();
          //OSTimeDlyHMSM(0,0,0,5,OS_OPT_TIME_PERIODIC,&err);     //延时500ms	
				  break;		
				case STATE_DHCP_REQUEST :
					send_DHCP_REQUEST();
				  break;
				case STATE_DHCP_REREQUEST :				
					send_DHCP_REQUEST();
				  break;
				default :
				break;
			}
			dhcp_time = 0;
			dhcp_tick_next = dhcp_time + DHCP_WAIT_TIME;
			dhcp_retry_count++;
		}
	} else {
			switch ( dhcp_state ) {
				case STATE_DHCP_DISCOVER :
        //默认IP配置 静态IP设置
					 setMR(MR_RST);
					 getMR(); 
          sprintf((char*)ip_mode,"STATIC_MODE");//工作区域
          Set_Default();
          OSTaskDel(&DhcpTaskTCB,&err);	
//					reset_DHCP_timeout();
//					send_DHCP_DISCOVER();
//					dhcp_state = STATE_DHCP_DISCOVER;
        break;		
				default :
//          Set_Default();
//          OSTaskDel(&DhcpTaskTCB,&err);	
					reset_DHCP_timeout();
					send_DHCP_DISCOVER();
					dhcp_state = STATE_DHCP_DISCOVER;
				break;
			}

	}
	return ret;
}
/***********************************************************************************
 * @brief DHCP函数
 * ex:       获取ip地址等参数
 * @par   
 * None
 * @retval
 **********************************************************************************/
static uint8_t DHCP_run(void)
{
	uint8_t  type;
	uint8_t  ret;

	if(dhcp_state == STATE_DHCP_STOP) return DHCP_STOPPED;

	if(getSn_SR(SOCK_DHCP) != SOCK_UDP)
	   socket(SOCK_DHCP, Sn_MR_UDP, DHCP_CLIENT_PORT, 0x00);

	ret = DHCP_RUNNING;	
	type = parseDHCPMSG();
	
	switch ( dhcp_state ) {
	   case STATE_DHCP_READY :
         DHCP_allocated_ip[0] = 0;
         DHCP_allocated_ip[1] = 0;
         DHCP_allocated_ip[2] = 0;
         DHCP_allocated_ip[3] = 0;
		     
   		   send_DHCP_DISCOVER();

		     dhcp_time = 0;
   		   dhcp_state = STATE_DHCP_DISCOVER;
   		   break;
		 case STATE_DHCP_DISCOVER :
			   if (type == DHCP_OFFER)
					 {
            DHCP_allocated_ip[0] = pDHCPMSG->yiaddr[0];
            DHCP_allocated_ip[1] = pDHCPMSG->yiaddr[1];
            DHCP_allocated_ip[2] = pDHCPMSG->yiaddr[2];
            DHCP_allocated_ip[3] = pDHCPMSG->yiaddr[3];
            
				    send_DHCP_REQUEST();
						dhcp_time = 0;
				    dhcp_state = STATE_DHCP_REQUEST;
			    } 
				else 
//            send_DHCP_DISCOVER();
//            delay_ms(500);
            //OSTimeDlyHMSM(0,0,0,5,OS_OPT_TIME_PERIODIC,&err);     //延时500ms	
						ret = check_DHCP_timeout();
        break;
		case STATE_DHCP_REQUEST :
			  if (type == DHCP_ACK) 
				{
				  if (check_DHCP_leasedIP()) 
					{
						dhcp_ip_assign();
						reset_DHCP_timeout();
//            TIM_Cmd(TIM3,DISABLE);
//            OSTaskDel(&DhcpTaskTCB,&err);	
						dhcp_state = STATE_DHCP_LEASED;
				  } 
					else   //IP冲突从新开始获取
					{
					 reset_DHCP_timeout();
					 dhcp_ip_conflict();
					 dhcp_state = STATE_DHCP_READY;
				  }
			  } 
				else if (type == DHCP_NAK) 
				{
				  reset_DHCP_timeout();
				  dhcp_state = STATE_DHCP_DISCOVER;
			  } 
				else 
					ret = check_DHCP_timeout();
		    break;
		case STATE_DHCP_LEASED :
		   ret = DHCP_IP_LEASED;		  
			 if ((dhcp_lease_time != DEFAULT_LEASETIME) && ((dhcp_lease_time/2) < dhcp_time/10)) 
       {
				type = 0;
				OLD_allocated_ip[0] = DHCP_allocated_ip[0];
				OLD_allocated_ip[1] = DHCP_allocated_ip[1];
				OLD_allocated_ip[2] = DHCP_allocated_ip[2];
				OLD_allocated_ip[3] = DHCP_allocated_ip[3];
				
				DHCP_XID++;
				send_DHCP_REQUEST();				
				reset_DHCP_timeout();
				dhcp_state = STATE_DHCP_REREQUEST;
			 }
		    break;
		case STATE_DHCP_REREQUEST :
		   ret = DHCP_IP_LEASED;
			if (type == DHCP_ACK) 
      {
				dhcp_retry_count = 0;
				if (OLD_allocated_ip[0] != DHCP_allocated_ip[0] || 
				    OLD_allocated_ip[1] != DHCP_allocated_ip[1] ||
				    OLD_allocated_ip[2] != DHCP_allocated_ip[2] ||
				    OLD_allocated_ip[3] != DHCP_allocated_ip[3]) 
				{
					ret = DHCP_IP_CHANGED;
					dhcp_ip_update();			
				}          				
				reset_DHCP_timeout();
				dhcp_state = STATE_DHCP_LEASED;
			} 
			else if (type == DHCP_NAK) 
			{
				reset_DHCP_timeout();
				dhcp_state = STATE_DHCP_DISCOVER;
			} 
			else 
        ret = check_DHCP_timeout();
	   	break;
		default :
   		break;
	}
	return ret;
}


/***********************************************************************************
 * @brief DHCP任务函数
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
void dhcp_task(void *p_arg)
{
  OS_ERR err;
  
  while(1){
    OSTimeDlyHMSM(0,0,0,5,OS_OPT_TIME_PERIODIC,&err);     //延时500ms		
    DHCP_run();
  }
}
